package com.atguigu.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.mapper.OaProcessMapper;
import com.atguigu.model.process.Process;
import com.atguigu.model.process.ProcessRecord;
import com.atguigu.model.process.ProcessTemplate;
import com.atguigu.model.system.SysUser;
import com.atguigu.security.custom.LoginUserInfoHelper;
import com.atguigu.service.*;
import com.atguigu.vo.process.ApprovalVo;
import com.atguigu.vo.process.ProcessFormVo;
import com.atguigu.vo.process.ProcessQueryVo;
import com.atguigu.vo.process.ProcessVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.activiti.api.process.runtime.events.ProcessCancelledEvent;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.*;
import java.util.zip.ZipInputStream;

@Service
public class OaProcessServiceImpl extends ServiceImpl<OaProcessMapper, Process> implements OaProcessService {
    @Autowired
    private OaProcessMapper oaProcessMapper;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private OaProcessTemplateService oaProcessTemplateService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private OaProcessRecordService oaProcessRecordService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private MessageService messageService;

    @Override
    public IPage<ProcessVo> selectPage(IPage<ProcessVo> page1, ProcessQueryVo processQueryVo) {
      return   oaProcessMapper.getPage(page1,processQueryVo);
    }

    @Override
    public void deployByZip(String processDefinitionPath) {
        FileInputStream fileInputStream=null;
        ZipInputStream zipInputStream=null;
        try {
        File file=new File(processDefinitionPath);
             fileInputStream = new FileInputStream(file);
             zipInputStream = new ZipInputStream(fileInputStream);
            repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
                zipInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void startUp(ProcessFormVo processFormVo) {
        //根据token认证时threadLocal存储的用户id获取用户信息
        Long userId = LoginUserInfoHelper.getUserId();
        SysUser sysUser = sysUserService.getUserById(userId.intValue());
        //根据模板id获取模板信息
        Long processTemplateId = processFormVo.getProcessTemplateId();
        ProcessTemplate processTemplate = oaProcessTemplateService.getById(processTemplateId);
        Process process = new Process();
        BeanUtils.copyProperties(processFormVo,process);
        process.setProcessCode(System.currentTimeMillis()+"");
        process.setUserId(userId);
        process.setStatus(1);
        process.setTitle(sysUser.getName()+"发起"+processTemplate.getName()+"申请");
        oaProcessMapper.insert(process);
        //开启流程实例
        Map<String,Object> variables=new HashMap<>();
        String formValues = processFormVo.getFormValues();
        JSONObject jsonObject = JSON.parseObject(formValues);
        JSONObject formData = jsonObject.getJSONObject("formData");
        Map<String,Object> map=new HashMap<>();
        for (Map.Entry<String, Object> entry : formData.entrySet()) {
            map.put(entry.getKey(),entry.getValue());
        }
        variables.put("data",map);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processTemplate.getProcessDefinitionKey(), process.getId().toString(), variables);
        process.setProcessInstanceId(processInstance.getId());
        //获取下一个审批人
        List<Task> taskList = getCurrentTaskList(processInstance.getId());
        List<String> assignList=new ArrayList<>();
        if (!CollectionUtils.isEmpty(taskList)){
            for (Task task : taskList) {
                String assignee = task.getAssignee();
              SysUser sysUser1= sysUserService.getByUsername(assignee);
                assignList.add(sysUser1.getName());
                //推送给下一个审批人，后续完善
                messageService.pushPendingMessage(sysUser1.getId(),process.getId(),task.getId());
            }
        }
        process.setDescription("等待"+ StringUtils.join(assignList,",")+"审批");
        oaProcessMapper.updateById(process);
        //记录提交记录
        oaProcessRecordService.record(process.getId(),1,"发起申请");



    }

    @Override
    public IPage<ProcessVo> findPending(IPage<ProcessVo> pageParam) {
        String userName = LoginUserInfoHelper.getUserName();
        TaskQuery query = taskService.createTaskQuery().taskAssignee(userName).orderByTaskCreateTime().desc();
        List<Task> tasks = query.listPage((int) ((pageParam.getCurrent() - 1) * pageParam.getSize()), (int) pageParam.getSize());
        List<ProcessVo> processVoList=new ArrayList<>();
        if (!CollectionUtils.isEmpty(tasks)){
            for (Task task : tasks) {
                String processInstanceId = task.getProcessInstanceId();
                LambdaQueryWrapper<Process> lambdaQueryWrapper=new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(Process::getProcessInstanceId,processInstanceId);
                Process process = oaProcessMapper.selectOne(lambdaQueryWrapper);
                ProcessVo processVo = new ProcessVo();
                BeanUtils.copyProperties(process,processVo);
                processVo.setTaskId(task.getId());
                processVoList.add(processVo);
            }
        }
        IPage<ProcessVo> page=new Page<>(pageParam.getCurrent(),pageParam.getSize(),query.count());
        page.setRecords(processVoList);
        return page;
    }

    @Override
    public Map<String, Object> show(Integer processId) {
        Map<String, Object> map=new HashMap<>();
        Process process = oaProcessMapper.selectById(processId);
        List<ProcessRecord> processRecordList = oaProcessRecordService.list(new LambdaQueryWrapper<ProcessRecord>().eq(ProcessRecord::getProcessId, processId));
        map.put("process",process);
        map.put("processRecordList",processRecordList);
        List<Task> currentTaskList = getCurrentTaskList(process.getProcessInstanceId());
        boolean isApprove=false;
        if (!CollectionUtils.isEmpty(currentTaskList)){
            for (Task task : currentTaskList) {
                String assignee = task.getAssignee();
                if (LoginUserInfoHelper.getUserName().equals(assignee)){
                    isApprove=true;
                }
            }
        }
        map.put("isApprove",isApprove);
        return map;
    }

    /**
     * 审批人 完成审批通过或审批拒绝
     * 1.如果审批通过当前审批人完成任务  如果审批拒绝就改变任务流向直接到终点
     * 2.插入processRecord数据，记录流程信息
     * 3.判断当前任务是否还有审批人，如果还有，说明上一步审批通过并且又有了下一个审批人
     * 这时需要修改process中的描述（改为具体审批人的描述）和status（改为审批中）
     * 4.如果当前任务已经没有审批人，则有两种情况：
     * 4.1审批通过的情况下没有审批人：这时修改process中的status和description
     * 4.2审批拒绝的情况下没有审批人：这时修改process中的status和description
     * @param approvalVo
     */
    @Override
    @Transactional

    public void approve(ApprovalVo approvalVo) {
        Integer status = approvalVo.getStatus();
        String taskId = approvalVo.getTaskId();
        Long processId = approvalVo.getProcessId();
        Process process = oaProcessMapper.selectById(processId);

        //审批通过
        if (status.intValue()==1){
            //完成本步流程
            taskService.complete(taskId);
        }else{
            endTask(taskId);
        }
        String description=status.intValue()==1?"已通过":"驳回";
        oaProcessRecordService.record(processId,approvalVo.getStatus(),description);
        List<Task> currentTaskList = getCurrentTaskList(process.getProcessInstanceId());
        if (!CollectionUtils.isEmpty(currentTaskList)){
            List<String> assigneeList=new ArrayList<>();
            for (Task task : currentTaskList) {
                String assignee = task.getAssignee();
                SysUser sysUser = sysUserService.getByUsername(assignee);
                assigneeList.add(sysUser.getName());
                //后续整合微信通知下一个审批人
                messageService.pushPendingMessage(sysUser.getId(),processId,task.getId());
            }
            process.setStatus(1);
            process.setDescription("等待"+StringUtils.join(assigneeList,",")+"审批");

        }else{
            if (status.intValue()==1){
                //审批通过并且没有审批人的情况下
                process.setStatus(2);
                process.setDescription("审批完成（同意）");
            }else{
                //审批没有通过并且没有审批人的情况下
                process.setStatus(-1);
                process.setDescription("审批完成（拒绝）");
            }
        }
        this.updateById(process);
        //推送消息给申请人
        messageService.pushProcessedMessage(process.getId(), process.getUserId(), approvalVo.getStatus());

    }

    @Override
    public IPage<ProcessVo> findProcessed(IPage<ProcessVo> pageParam) {
        String userName = LoginUserInfoHelper.getUserName();
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().finished().taskAssignee(userName).orderByTaskCreateTime().desc();
        long count = historicTaskInstanceQuery.count();
        List<HistoricTaskInstance> taskInstanceList = historicTaskInstanceQuery.listPage((int) ((pageParam.getCurrent() - 1) * pageParam.getSize()), (int) pageParam.getSize());

            List<ProcessVo> processVoList=new ArrayList<>();
        if (!CollectionUtils.isEmpty(taskInstanceList)){
            for (HistoricTaskInstance historicTaskInstance : taskInstanceList) {
                String processInstanceId = historicTaskInstance.getProcessInstanceId();
                LambdaQueryWrapper<Process> lambdaQueryWrapper=new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(Process::getProcessInstanceId,processInstanceId);
                Process process = oaProcessMapper.selectOne(lambdaQueryWrapper);
                ProcessVo processVo = new ProcessVo();
                BeanUtils.copyProperties(process,processVo);
                processVo.setTaskId(historicTaskInstance.getId());
                processVoList.add(processVo);
            }
        }
        return new Page<ProcessVo>(pageParam.getCurrent(),pageParam.getSize(),count).setRecords(processVoList);

    }
    @Override
    public IPage<ProcessVo> findStarted(IPage<ProcessVo> pageParam) {
        Long userId = LoginUserInfoHelper.getUserId();
        ProcessQueryVo processQueryVo = new ProcessQueryVo();
        processQueryVo.setUserId(userId);

        IPage<ProcessVo> page = oaProcessMapper.getPage(pageParam, processQueryVo);
        for (ProcessVo record : page.getRecords()) {
            record.setTaskId("0");
        }
        return page;

    }

    private void endTask(String taskId) {
        //  当前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        //找到结束事件
        List endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        // 并行任务可能为null
        if(CollectionUtils.isEmpty(endEventList)) {
            return;
        }
        FlowNode endFlowNode = (FlowNode) endEventList.get(0);
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());

        //  临时保存当前活动的原始方向
        List originalSequenceFlowList = new ArrayList<>();
        originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
        //  清理活动方向
        currentFlowNode.getOutgoingFlows().clear();

        //  建立新方向
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(currentFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        List newSequenceFlowList = new ArrayList<>();
        newSequenceFlowList.add(newSequenceFlow);
        //  当前节点指向新的方向
        currentFlowNode.setOutgoingFlows(newSequenceFlowList);

        //  完成当前任务
        taskService.complete(task.getId());
    }

    private List<Task> getCurrentTaskList(String processInstanceId) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        return list;
    }
}
